/************************************************************************/
/* Used planet texture are from:                                        */
/* Copyright (c) James Hastings-Trew                                    */
/* http://planetpixelemporium.com/planets.html                          */
/************************************************************************/
#include "ForceScene.h"

#include <iostream>

ForceScene::ForceScene()
{
    this->planetTextures = NULL;
    this->currentMaxTimestep = 0.0f;
    this->currentMaxIter = 0;
}

ForceScene::~ForceScene()
{
    CleanScene();
}

void ForceScene::PrepareScene(NxScene *scene)
{
    PhysxLogic::cam = new Camera(NxVec3(1000.0f, 800.0f, 1000.0f), NxVec3(-0.7f,-0.5f,-0.7f), (float)glutGet(GLUT_WINDOW_WIDTH)/(float)glutGet(GLUT_WINDOW_HEIGHT), 60.0f, 0.1f, 10E09);

    //default material
    NxMaterial *defaultMaterial = scene->getMaterialFromIndex(0);
    defaultMaterial->setRestitution(0.0f);
    defaultMaterial->setStaticFriction(0.0f);
    defaultMaterial->setDynamicFriction(0.0f);

    currentMaxTimestep = (24.0f * 60.0f * 60.0f) / 60.0f; //circa 24h pro simulationsschritt
    currentMaxIter = 64;
    PhysxLogic::physicsScene->setTiming(currentMaxTimestep, currentMaxIter, NX_TIMESTEP_FIXED);

    this->planetTextures = new DevilTexture[10];
    this->planetTextures[0].Load("..\\res\\tex\\planets\\sunmap.jpg");
    this->planetTextures[1].Load("..\\res\\tex\\planets\\mercurymap.jpg");
    this->planetTextures[2].Load("..\\res\\tex\\planets\\venusmap.jpg");
    this->planetTextures[3].Load("..\\res\\tex\\planets\\earthmap.jpg");
    this->planetTextures[4].Load("..\\res\\tex\\planets\\marsmap.jpg");
    this->planetTextures[5].Load("..\\res\\tex\\planets\\jupitermap.jpg");
    this->planetTextures[6].Load("..\\res\\tex\\planets\\saturnmap.jpg");
    this->planetTextures[7].Load("..\\res\\tex\\planets\\uranusmap.jpg");
    this->planetTextures[8].Load("..\\res\\tex\\planets\\neptunemap.jpg");
    this->planetTextures[9].Load("..\\res\\tex\\planets\\plutomap.jpg");

    Planet *sun = new Planet(NxVec3(0.0f, 0.0f, 0.0f), "sun", 1.989E30, 6.69E05, 100, NxVec3(0, 0, 0), NxVec3(0, 1.0f/2332800.0f, 0), NxVec3(1.0f, 1.0f, 0.0f), &(this->planetTextures[0]), scene);
    Planet *mercury = new Planet(NxVec3(5.79E10, 0.0f, 0.0f), "mercury", 3.302E23, 2.44E03, 40, NxVec3(0, 0, -47870), NxVec3(0, 1.0f/5067360.0f, 0), NxVec3(0.66f, 0.66f, 0.66f), &(this->planetTextures[1]), scene);
    Planet *venus = new Planet(NxVec3(1.08E11, 0.0f, 0.0f), "venus", 4.869E24, 6.05E03, 40, NxVec3(0, 0, -35020), NxVec3(0, -1.0f/20995200.0f, 0), NxVec3(0.86f, 0.69f, 0.33f), &(this->planetTextures[2]), scene);
    Planet *earth = new Planet(NxVec3(1.5E11, 0.0f, 0.0f), "earth", 5.974E24, 6.37E03, 40, NxVec3(0, 0, -29780), NxVec3(0, 1.0f/86400.0f, 0), NxVec3(0.15f, 0.31f, 0.59f), &(this->planetTextures[3]), scene);
    Planet *mars = new Planet(NxVec3(2.28E11, 0.0f, 0.0f), "mars", 6.419E23, 3.39E03, 40, NxVec3(0, 0, -24130), NxVec3(0, 1.0f/88992.0f, 0), NxVec3(0.5f, 0.0f, 0.0f), &(this->planetTextures[4]), scene);
    Planet *jupiter = new Planet(NxVec3(7.78E11, 0.0f, 0.0f), "jupiter", 1.899E27, 6.92E04, 80, NxVec3(0, 0, -13070), NxVec3(0, 1.0f/35424.0f, 0), NxVec3(0.82f, 0.66f, 0.43f), &(this->planetTextures[5]), scene);
    Planet *saturn = new Planet(NxVec3(1.43E12, 0.0f, 0.0f), "saturn", 5.685E26, 5.73E04, 150, NxVec3(0, 0, -9690), NxVec3(0, 1.0f/38016.0f, 0), NxVec3(0.94f, 0.9f, 0.78f), &(this->planetTextures[6]), scene);
    Planet *uranus = new Planet(NxVec3(2.88E12, 0.0f, 0.0f), "uranus", 8.683E25, 2.53E04, 300, NxVec3(0, 0, -6810), NxVec3(0, -1.0f/62208.0f, 0), NxVec3(0.63f, 0.76f, 0.84f), &(this->planetTextures[7]), scene);
    Planet *neptune = new Planet(NxVec3(4.50E12, 0.0f, 0.0f), "neptune", 1.024E26, 2.50E04, 500, NxVec3(0, 0, -5430), NxVec3(0, 1.0f/62208.0f, 0), NxVec3(0.29f, 0.45f, 0.69f), &(this->planetTextures[8]), scene);
    Planet *pluto = new Planet(NxVec3(5.91E12, 0.0f, 0.0f), "pluto", 1.250E22, 1.20E03, 80, NxVec3(0, 0, -4720), NxVec3(0, -1.0f/551232.0f, 0), NxVec3(0.59f, 0.59f, 0.59f), &(this->planetTextures[9]), scene);

    planets.push_back(sun);
    planets.push_back(mercury);
    planets.push_back(venus);
    planets.push_back(earth);
    planets.push_back(mars);
    planets.push_back(jupiter);
    planets.push_back(saturn);
    planets.push_back(uranus);
    planets.push_back(neptune);
    planets.push_back(pluto);
}

void ForceScene::CleanScene()
{
    for(std::list<Planet*>::iterator it = planets.begin(); it != planets.end(); ++it)
    {
        Planet *p = *it;
        delete p;
    }
    planets.clear();

    delete[] this->planetTextures;
    delete PhysxLogic::cam;
}

void ForceScene::Update()
{
    for(std::list<Planet*>::iterator it = planets.begin(); it != planets.end(); ++it)
    {
        Planet *p = *it;
        p->Update();
    }
}

void ForceScene::Draw()
{
    for(std::list<Planet*>::iterator it = planets.begin(); it != planets.end(); ++it)
    {
        Planet *p = *it;
        if(p->GetName().compare("sun")==0)
            glDisable(GL_LIGHTING);
        if(p->GetVisibility())
            p->Draw();
        if(p->GetName().compare("sun")==0)
            glEnable(GL_LIGHTING);
    }
}

void ForceScene::HandleKeyboardEvent(unsigned char key, int x, int y)
{
    switch(key)
    {
        case 'w': //UP
        {
            NxVec3 dir = PhysxLogic::cam->GetDirection();
            dir.normalize();
            PhysxLogic::cam->MoveBy(dir*100.0);
            break;
        }
        case 's': //DOWN
        {
            NxVec3 dir = PhysxLogic::cam->GetDirection();
            dir.normalize();
            PhysxLogic::cam->MoveBy(-dir*100.0);
            break;
        }
        case 'd': //RIGHT
        {
            NxVec3 dir = PhysxLogic::cam->GetSideNormal();
            dir.normalize();
            PhysxLogic::cam->MoveBy(dir*100.0);
            break;
        }
        case 'a': //LEFT
        {
            NxVec3 dir = PhysxLogic::cam->GetSideNormal();
            dir.normalize();
            PhysxLogic::cam->MoveBy(-dir*100.0);
            break;
        }
        case '0':		
        case '1':		
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        {
            int keyNumber = (int)key - '0';
            int planetCounter = 0;
            for(std::list<Planet*>::iterator it = planets.begin(); it != planets.end(); ++it)
            {
                if(keyNumber == planetCounter)
                {
                    Planet *p = *it;
                    p->SetVisibility(!p->GetVisibility());
                    break;
                }
                planetCounter++;
            }
            break;
        }
        case '+':
        {
            currentMaxTimestep += (60*60*12)/60.0f; 
            PhysxLogic::physicsScene->setTiming(currentMaxTimestep, currentMaxIter, NX_TIMESTEP_FIXED);
            break;
        }
        case '-':
        {
            currentMaxTimestep -= (60*60*12)/60.0f; 
            if(currentMaxTimestep <= 0) currentMaxTimestep = 21600.0f/60.0f;
            PhysxLogic::physicsScene->setTiming(currentMaxTimestep, currentMaxIter, NX_TIMESTEP_FIXED);
            break;
        }
    }
}

void ForceScene::HandleKeyboardSpecialEvent(int key, int x, int y)
{
    switch(key)
    {
        case GLUT_KEY_F2:
        {
            if(PhysxLogic::IsDebugRenderingEnabled())
            {
                PhysxLogic::SetDebugRenderingEnabled(false);
                PhysxLogic::debugRenderer->DeactivateDebugVisualization(NX_VISUALIZE_FORCE_FIELDS);
                PhysxLogic::debugRenderer->DeactivateDebugVisualization(NX_VISUALIZE_COLLISION_SHAPES);
            }
            else
            {
                PhysxLogic::SetDebugRenderingEnabled(true);
                PhysxLogic::debugRenderer->ActivateDebugVisualization(NX_VISUALIZE_FORCE_FIELDS);
                PhysxLogic::debugRenderer->ActivateDebugVisualization(NX_VISUALIZE_COLLISION_SHAPES);
            }
            break;
        }
    }
}

void ForceScene::HandleMouseClickEvent(int button, int state, int x, int y)
{

}

void ForceScene::HandleMousePressedMovementEvent(int x, int y, int dx, int dy)
{

}